/*
 * COPYRIGHT:	2010 Christopher Smith, licenced under the GNU GPL v2; see COPYING in the top level directory
 * PROJECT:		sdedit
 * FILE:		lookup.cpp
 * PURPOSE:		virtual interfaces for sid and guid lookup and enumeration
 *				
 */

namespace Lookup
{

//Complete or CompleteExcept will be called (CompleteExcept with a cancel exception if canceled)-- exactly one of these
template <class T> struct CompletionTarget : auto_refctd_std_base
{
	virtual void Complete(T const *Result) = 0;
	virtual void CompleteExcept(EXCEPTION_RECORD const *ExceptionRecord) = 0;
	virtual ~CompletionTarget() {}
};

template <class T> LONG CompleteExceptSEHFilter(CompletionTarget<T> *Ct, EXCEPTION_RECORD const *ExceptionRecord)
{
	if(ExceptionRecord->ExceptionCode == STATUS_COUNT_CANCEL_HANDLERS)
		return EXCEPTION_CONTINUE_EXECUTION;

	if(IsExpectedException(ExceptionRecord->ExceptionCode))
	{
		Ct->CompleteExcept(ExceptionRecord);
		return EXCEPTION_EXECUTE_HANDLER;
	}

	return EXCEPTION_CONTINUE_SEARCH;
}

template <class T> struct Translator : auto_refctd_std_base
{
	virtual void LookupData(CompletionTarget<WCHAR> *Ct, T const *Data) = 0;
	virtual void LookupName(CompletionTarget<T> *Ct, PCWSTR Name) = 0;
	virtual ~Translator() {}
};

struct Translators : auto_refctd_std_base
{
	auto_refct<Translator<SID> > SidTranslator;
	auto_refct<Translator<GUID> > GuidTypeTranslator;
	auto_refct<Translator<GUID> > GuidInhTypeTranslator;
};

template <class T> struct Enumerator;

template <class T> struct ChildrenWalkDest
{
	virtual void BreakProc() = 0;
	virtual void ChildProc(PCWSTR Name, Enumerator<T> *Child) = 0;
};

template <class T> struct EntriesWalkDest
{
	virtual void BreakProc() = 0;
	virtual void EntryProc(PCWSTR Name, T const &Data) = 0;
};

template <class T> struct Enumerator : auto_refctd_std_base
{
	virtual void WalkChildren(ChildrenWalkDest<T> &Dest) = 0;
	virtual void WalkEntries(EntriesWalkDest<T> &Dest) = 0;
	virtual ~Enumerator() {}
};

struct Enumerators : auto_refctd_std_base
{
	auto_refct<Enumerator<SID> > SidEnumerator;
	auto_refct<Enumerator<GUID> > GuidTypeEnumerator;
	auto_refct<Enumerator<GUID> > GuidInhTypeEnumerator;
};

static const ULONG DOMAIN_INFO_HAS_HOST =		0x00000002;
static const ULONG DOMAIN_INFO_HAS_SEARCHHOST =	0x00000004;
static const ULONG DOMAIN_INFO_HAS_FORESTNAME =	0x00000008;
static const ULONG DOMAIN_INFO_NETDOMAIN =		0x00010000; //at most one of NET or LOCAL domain (neither if unknown)
static const ULONG DOMAIN_INFO_LOCALDOMAIN =	0x00020000;
static const ULONG DOMAIN_INFO_NTDS =			0x00040000;
static const ULONG DOMAIN_INFO_NOT_NTDS =		0x00080000;

struct DOMAIN_INFO
{
	ULONG Flags;
	SID const *DomainSid;
	PCWSTR DomainName;
	PCWSTR Host OPTIONAL; //a host that can provide domain details
	PCWSTR SearchHost OPTIONAL; //a host that can find a host to provide domain details
	PCWSTR ForestName OPTIONAL; //dns name of the root forest
};

typedef Enumerator<DOMAIN_INFO> DomainEnumerator;

struct DomainAccountEnumerator : auto_refctd_std_base
{
	virtual Enumerator<SID> *NewEnum(DOMAIN_INFO const &Info) = 0;
};

struct DomainInfo //same as DOMAIN_INFO, but with ownership of data
{
	ULONG Flags;
	auto_szpod<SID> DomainSid;
	auto_szpod<WCHAR> DomainName;
	auto_szpod<WCHAR> Host OPTIONAL; //a host that can provide domain details
	auto_szpod<WCHAR> SearchHost OPTIONAL; //a host that can find a host to provide domain details
	auto_szpod<WCHAR> ForestName OPTIONAL; //dns name of the root forest

	DomainInfo(DOMAIN_INFO const &Di) :
		Flags(Di.Flags),
		DomainSid(Di.DomainSid),
		DomainName(Di.DomainName),
		Host(Di.Host),
		SearchHost(Di.Host),
		ForestName(Di.ForestName)
	{}

	operator DOMAIN_INFO() const
	{
		DOMAIN_INFO Di = {Flags, DomainSid, DomainName, Host, SearchHost, ForestName};
		return Di;
	}
};

}//namespace Lookup